package learning.utils;

import java.time.Duration;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;

public class RetryExecutor {

    private final int maxRetries;
    private final Duration retryDelay;
    private final Predicate<Throwable> shouldRetryPredicate;

    public RetryExecutor(int maxRetries, Duration retryDelay, Predicate<Throwable> shouldRetryPredicate) {
        this.maxRetries = maxRetries;
        this.retryDelay = retryDelay;
        this.shouldRetryPredicate = shouldRetryPredicate;
    }

    public <T> T execute(Callable<T> callable) throws Exception {
        int attempt = 0;
        while (true) {
            try {
                return callable.call();
            } catch (Exception e) {
                attempt++;
                if (attempt > maxRetries || !shouldRetryPredicate.test(e)) {
                    throw e;
                }
                // Log the failure and sleep before retrying
                System.out.printf("第 %d 次尝试失败，将在 %s 后进行下一次重试，异常信息：%s%n",
                        attempt, retryDelay, e.getMessage());
                TimeUnit.MILLISECONDS.sleep(retryDelay.toMillis());
            }
        }
    }
}

